// Do it without expectation. Wish for nothing. Care for everything. Happiness will be in between.

package gimreader;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;

class Gimreader {

    private static void createAndShowGUI(Object root) {
        //System.out.println("Created GUI on EDT? " + SwingUtilities.isEventDispatchThread());
        JFrame f = new JFrame("Swing Paint Demo");
        f.setPreferredSize(new Dimension(1100, 700)); //TODO set pref size...
        f.getContentPane().setLayout(new FlowLayout());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        String filename = File.separator;
        JFileChooser fc = new JFileChooser(new File(filename));
        Action openAction = new OpenFileAction(f, fc);

        JMenu menuFile = new JMenu();
        menuFile.setText("File");
        JMenuItem menuitemOpen = new JMenuItem();
        menuitemOpen.setText("Open");
        menuitemOpen.addActionListener(openAction);
        menuFile.add(menuitemOpen);
        JMenuBar MenuBar1 = new JMenuBar();
        MenuBar1.add(menuFile);
        f.setJMenuBar(MenuBar1);

        JTreeTable MainTable = new JTreeTable(new GimModel(root));
        MainTable.setPreferredScrollableViewportSize(new Dimension(990, 500));
        f.add(new JScrollPane(MainTable));
        f.add(new JScrollPane(new MainPanel()));

        f.pack();
        f.setVisible(true);

    }

    static class MainPanel extends JPanel {

        MainPanel() {
            setBorder(BorderFactory.createLineBorder(Color.red));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(600, 200);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            // Draw Text
            g.drawString("Custom Panel!", 10, 20);
            //g.setColor(Color.white);
            //g.drawLine(5, 150, 400, 150);
            //g.draw3DRect(50, 50, 30, 40, true);
        }
    }

    // print debug messages to output.
    static boolean debugmode = true;

    static long utime(String s) {
        DateFormat sdf;
        long longDate = -1;
        if (s.length() == 23) {
            if (".".equals(s.substring(19, 20))) {
                sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            } else {
                sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS");
            }
            Date date;
            try {
                date = sdf.parse(s);
                longDate = date.getTime();
            } catch (Exception e) {
                return -1;
            }
        }
        return longDate;

    }

    static long findtime(String s) {
        Pattern p = Pattern.compile("(^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\,\\d{3})");
        Matcher m = p.matcher(s);
        if (m.find()) {
            return utime(m.group(1));
        } else {
            return 0;
        }
    }

    public static void main(String[] args) {
        TreeNode<JobEntries> root = new TreeNode<>(new JobEntries()); // TODO Инициализировать только после нахождения первой записи относящейся к джиму....         
        ArrayList DATA = new ArrayList();                   // records with data from log files 
        ArrayList LOGS = new ArrayList();                   // list of log files
        ArrayList SOURCE = new ArrayList();                 // list of sources (IDB's)
        HashMap StartPoints = new HashMap();                // Used to track start time of events, then to link with an end of the event        

        if (args.length > 0) {
            try {
                File dir = new File(args[0]);
                String[] entries = dir.list();
                int logindex = 0;
                for (int i = 0; i < entries.length; i++) {
                    int line = 0;          // saves the line position in the file    
                    long ltime;            // timestamp in unix format
                    String name = args[0] + entries[i];
                    System.out.println("Processing Log file: " + name);

                    // erase StartPoints.  
                    StartPoints.clear();

                    //<editor-fold defaultstate="collapsed" desc="Parsing... ">
                    try {
                        BufferedReader logfile = new BufferedReader(new FileReader(name));
                        String currentstr;

                        LogFiles l = new LogFiles(name);
                        LOGS.add(l);
                        logindex = LOGS.indexOf(l);
                        l.SetLogID(logindex);
                        String savedate = "";
                        try {
                            while ((currentstr = logfile.readLine()) != null) {
                                line++;                                
                                ltime = findtime(currentstr);
                                if (ltime > 0) {
                                    savedate = currentstr.substring(0, 11);
                                }
                                //
                                // setting Start and End time of the file
                                //
                                if (l.GetStart() == -1 && ltime > 0) {
                                    l.SetStart(ltime);
                                } else if (ltime >= l.GetStart()) {
                                    l.SetEnd(ltime);
                                }

                                // 
                                // Extract Started
                                //                                
                                if (currentstr.contains("Job 'Job_ExtractICON' started.")) {
                                    //ltime = utime(currentstr.substring(0, 24));
                                    JobEntries Job_Extract = new JobEntries(logindex, (byte)1, line);              // 1 - "Job_Extract"
                                    Job_Extract.SetStart(ltime);
                                    Job_Extract.SetComment(currentstr.substring(currentstr.indexOf("Version") + 9, currentstr.indexOf("built") - 2));
                                    DATA.add(Job_Extract);
                                    StartPoints.put("Job_Extract", DATA.indexOf(Job_Extract));
                                }

                                //
                                // Extract Completed
                                //
                                if (currentstr.contains("Job 'Job_ExtractICON' completed successfully.")) {
                                    //ltime = utime(currentstr.substring(0, 24));
                                    if (StartPoints.containsKey("Job_Extract")) {           // Job_Extract Start detected in the current log file
                                        JobEntries Job_Extract = (JobEntries) DATA.get((int) StartPoints.get("Job_Extract")); 
                                        Job_Extract.SetEnd(ltime);
                                        DATA.set((int) StartPoints.get("Job_Extract"), Job_Extract);
                                        StartPoints.remove("Job_Extract");
                                    } else {                                                //Job_Extract Start point wasn't detected yet
                                        JobEntries Job_Extract = new JobEntries(logindex, (byte)1, line);   // 1 - "Job_Extract"
                                        Job_Extract.SetEnd(ltime);
                                        DATA.add(Job_Extract);
                                    }
                                }

                                //
                                // Populating amount of Extracted RAWS from IDB (per table)
                                //
                                if (currentstr.contains("Extracted ")) {
                                    JobEntries JE = new JobEntries(logindex, (byte)2, line);     // 2 - "ExtractedRows"
                                    //ltime = utime(currentstr.substring(0, 24));
                                    JE.SetStart(ltime);
                                    // extracting source-table name
                                    String src = currentstr.substring(currentstr.indexOf("from") + 5, currentstr.indexOf("."));
                                    if (!SOURCE.contains(src)) {
                                        SOURCE.add(src);
                                    }
                                    JE.SetCustom(SOURCE.indexOf(src)); // IDB source is in Custom1
                                    JE.SetComment(currentstr.substring(currentstr.indexOf(".") + 1, currentstr.indexOf(", ")));
                                    // extracting amount of raws
                                    JE.SetRows(Integer.parseInt(currentstr.substring(currentstr.indexOf("Extracted ") + 10, currentstr.indexOf(" from"))));
                                    // extracting duration
                                    JE.SetDuration(Integer.parseInt(currentstr.substring(currentstr.indexOf("]") + 2, currentstr.indexOf(" ms"))));
                                    DATA.add(JE);
                                }

                                // 
                                // Transform Started
                                //                                
                                if (currentstr.contains("Job 'Job_TransformGIM' started.")) {
                                    //ltime = utime(currentstr.substring(0, 24));
                                    JobEntries Job_Transform = new JobEntries(logindex, (byte)3, line);    // 3 - "Job_TransformGIM" 
                                    Job_Transform.SetStart(ltime);
                                    Job_Transform.SetComment(currentstr.substring(currentstr.indexOf("Version") + 9, currentstr.indexOf("built") - 2));
                                    DATA.add(Job_Transform);
                                    StartPoints.put("Job_Transform", DATA.indexOf(Job_Transform));
                                }

                                //
                                // Searching for Transformation delays due to not Extacted data
                                //
                                if (currentstr.contains("has been postponed due to delayed data")) {

                                    //Populate delayed chunks info
                                    if (debugmode) {
                                        System.out.println("Transformation of chunk delayed " + currentstr.substring(currentstr.indexOf("Transformation of chunk") + 23, currentstr.indexOf("has been"))); //TODO remove this code
                                    }
                                }

                                //
                                // Searching for Transform Completed Successfully
                                //
                                if (currentstr.contains("Job 'Job_TransformGIM' completed successfully.")) {
                                    //ltime = utime(currentstr.substring(0, 24));
                                    if (StartPoints.containsKey("Job_Transform")) {                     // Job_Transform Start detected in the current log file
                                        JobEntries Job_Transform = (JobEntries) DATA.get((int) StartPoints.get("Job_Transform"));
                                        Job_Transform.SetEnd(ltime);
                                        DATA.set((int) StartPoints.get("Job_Transform"), Job_Transform);
                                        StartPoints.remove("Job_Transform");
                                    } else {                                                //Job_Transform Start point wasn't detected yet
                                        JobEntries Job_Transform = new JobEntries(logindex, (byte)3, line);      // 3 - "Job_TransformGIM"
                                        Job_Transform.SetEnd(ltime);
                                        DATA.add(Job_Transform);
                                    }
                                }

                                //
                                // Search for Steps of Job_Transform
                                //
                                if (currentstr.contains("Job step ") && !(currentstr.endsWith("EXTRACT completed successfully.") || currentstr.endsWith("EXTRACT started."))) {
                                    //ltime = utime(currentstr.substring(0, 24));
                                    if (currentstr.endsWith("started.")) {
                                        String step = currentstr.substring(currentstr.indexOf("step") + 5, currentstr.indexOf(" started"));
                                        JobEntries JE = new JobEntries(logindex, (byte)4 , line);       // 4 - "TransformStep"
                                        JE.SetStart(ltime);
                                        JE.SetComment(step);
                                        DATA.add(JE);
                                        StartPoints.put(step, DATA.indexOf(JE));

                                    } else if (currentstr.endsWith("completed successfully.")) {
                                        String step = currentstr.substring(currentstr.indexOf("step") + 5, currentstr.indexOf(" completed"));
                                        if (StartPoints.containsKey(step)) {                     // Job_Transform Step start detected in the current log file
                                            JobEntries JE = (JobEntries) DATA.get((int) StartPoints.get(step));
                                            JE.SetEnd(ltime);
                                            DATA.set((int) StartPoints.get(step), JE);
                                            StartPoints.remove(step);
                                        } else {                                                //Job_Transform Step start point wasn't detected yet
                                            JobEntries JE = new JobEntries(logindex, (byte)3, line);   // 3 - "Job_TransformGIM"
                                            JE.SetEnd(ltime);
                                            JE.SetComment(step);
                                            DATA.add(JE);
                                        }
                                    } else if (currentstr.endsWith("failed.")) {
                                        // TODO to find a failed Transform step   
                                    }

                                }

                                /**
                                 * compare maxChunkTS= with the current
                                 * timestamp. 2014-11-26 04:52:08,114 INFO
                                 * ecp-1-1114 30000
                                 * TransformCoreVoice.transformIrf
                                 * (GIDB_G_IR_V[{37271755:
                                 * 1416748500-1416750300, maxChunkTS=2014-11-23
                                 * 13:53:23(1416750803), proc
                                 * status=MERGED_VOICE}],37510819) - enter
                                 * 2014-11-26 04:52:31,417 INFO ecp-1-1114 30000
                                 * TransformCoreVoice.transformIrf
                                 * (GIDB_G_IR_V[{37271898:
                                 * 1416748500-1416750300, maxChunkTS=2014-11-23
                                 * 13:54:35(1416750875), proc
                                 * status=MERGED_VOICE}],37510851) - enter
                                 * 2014-11-26 04:52:55,343 INFO ecp-1-1114 30000
                                 * TransformCoreVoice.transformIrf
                                 * (GIDB_G_IR_V[{37272045:
                                 * 1416748500-1416750300, maxChunkTS=2014-11-23
                                 * 13:55:42(1416750942), proc
                                 * status=MERGED_VOICE}],37510883) - enter
                                 *
                                 */
                                /**
                                 * 2014-11-24 23:08:43,552 WARN v-xform-0 20000
                                 * Interaction(1478364205):CallImpl@1A1I926TF11I3948RPCDRNBO6C005UBE
                                 * - missing "source party" 2014-11-24
                                 * 23:08:43,552 WARN v-xform-1 20000
                                 * Interaction(1478363911):CallImpl@1A1I926TF11I3948RPCDRNBO6C005U8R
                                 * - missing "source party" 2014-11-24
                                 * 23:08:43,552 WARN v-xform-3 20000
                                 * Interaction(1478411771) -
                                 * CALL(019RFVH65CA6VEKC181LGOTAES00E09R) has no
                                 * parties 2014-11-24 23:08:43,552 WARN
                                 * v-xform-0 20000 Interaction(1478364211) -
                                 * CALL(1A1I926TF11I3948RPCDRNBO6C005UBF) has no
                                 * parties
                                 */
                                //
                                // searhing for Failed Transforms
                                // 
                                if (currentstr.contains("unsuccessfully")) {

                                    // Populating failed transforms
                                }

                                //
                                // Aggregation module 
                                
// 2014-11-26 03:10:22,695 INFO  ecp-1-1      20103 Job 'Job_AggregateGIM' started. Version='8.1.401.05' built '2014-10-22 20:28:17 UTC'.
                                
                                if (currentstr.contains("Job 'Job_AggregateGIM' started.")) {
                                    //ltime = utime(currentstr.substring(0, 24));
                                    JobEntries JE = new JobEntries(logindex, (byte)5 , line);       // 5 - "Job_AggregateGIM"
                                    JE.SetStart(ltime);
                                    JE.SetComment(currentstr.substring(currentstr.indexOf("Version") + 9, currentstr.indexOf("built") - 2));
                                    DATA.add(JE);
                                    StartPoints.put("Job_AggregateGIM", DATA.indexOf(JE));
                                }
                                                                
// 2014-11-25 18:57:44,606 INFO  ecp-1-10186  20104 Job 'Job_AggregateGIM' completed successfully.                                                                                                
                                // Starting Aggregation of an Hierarchy
                                //
                                if (currentstr.contains("Starting aggregation of:")) {
                                    //System.out.println(" >>>>> agg date : " + savedate + currentstr.substring(0, 12));
                                    ltime = utime(savedate + currentstr.substring(0, 12));
                                    String hierarchy = currentstr.substring(currentstr.indexOf("of: ") + 4);
                                    JobEntries JE = new JobEntries(logindex, (byte)6, line);    // 6 - "AggHierarchy"
                                    JE.SetStart(ltime);
                                    JE.SetComment(hierarchy);
                                    DATA.add(JE);
                                    StartPoints.put(hierarchy, DATA.indexOf(JE));
                                }
                                
                                if (currentstr.contains("Finished aggregation of")) {
                                    //System.out.println(" <<<: " + currentstr);
                                    ltime = utime(savedate + currentstr.substring(0, 12));
                                    String hierarchy = currentstr.substring(currentstr.indexOf("of ") + 3, currentstr.indexOf(":", currentstr.indexOf("of ") + 4));  // don't ask ))
                                    if (StartPoints.containsKey(hierarchy)) {
                                        JobEntries JE = (JobEntries) DATA.get((int) StartPoints.get(hierarchy));
                                        JE.SetEnd(ltime);
                                        DATA.set((int) StartPoints.get(hierarchy), JE);
                                        StartPoints.remove(hierarchy);
                                        //System.out.println("h1 " + ltime+ " >>" +  hierarchy);
                                    } else {
                                        JobEntries JE = new JobEntries(logindex, (byte)6, line);    // 6 - "AggHierarchy"
                                        JE.SetEnd(ltime);
                                        JE.SetComment(hierarchy);
                                        DATA.add(JE);
                                        //System.out.println("h2 " + ltime+ " >>" +  hierarchy);
                                    }

                                }

                            }

                            //
                            // saving info about log file stats
                            //
                            LOGS.set(logindex, l);

                        } catch (IOException ex) {
                            System.out.println("Unable to read from file " + logfile);
                            return; //TODO remove this;
                        }

                        // Closing the file
                        try {
                            logfile.close();
                        } catch (IOException ex) {
                            System.out.println("Unable to close file " + logfile);
                        }
                        //</editor-fold>

                    } catch (FileNotFoundException e) {
                        System.out.print("file not found: " + name);
                    }
                }

                // sort ArrayList of Log files
                class MyLogsComp implements Comparator<LogFiles> {

                    @Override
                    public int compare(LogFiles e1, LogFiles e2) {
                        if (e1.GetStart() > e2.GetStart()) {
                            return 1;
                        } else {
                            return -1;
                        }
                    }
                }

                //<editor-fold defaultstate="collapsed" desc="sout LOGS... ">
                // TODO remove this debug code
                if (debugmode) {
                    Iterator itr = LOGS.iterator();
                    while (itr.hasNext()) {
                        LogFiles LF = (LogFiles) itr.next();
                        java.util.Date starttime = new java.util.Date((long) LF.starttime);
                        java.util.Date endtime = new java.util.Date((long) LF.endtime);

                        System.out.println(LOGS.indexOf(LF)
                                + " STime:" + starttime
                                + " Logfile: " + LF.LogFile
                                + " ETime: " + endtime
                                + " Duration: " + LF.GetNiceDuration());

                    }
                }
                // </editor-fold>

                Collections.sort(LOGS, new MyLogsComp());

                // Looking for logical conneections between log files
//                if ( LOGS.size() > 1 ) {
//                    Iterator it = LOGS.iterator();
//                    LogFiles LF1 = (LogFiles) it.next();
//                    while (it.hasNext()) {
//                        LogFiles LF2 = (LogFiles) it.next();
//                        
//                        
//                    }
//                }
                //<editor-fold defaultstate="collapsed" desc="sout LOGS... ">
                // TODO Remove this debug code         
                if (debugmode) {
                    Iterator itr = LOGS.iterator();
                    while (itr.hasNext()) {
                        LogFiles LF = (LogFiles) itr.next();
                        java.util.Date starttime = new java.util.Date((long) LF.starttime);
                        java.util.Date endtime = new java.util.Date((long) LF.endtime);

                        System.out.println(LOGS.indexOf(LF)
                                + " log id: " + LF.GetLogID()
                                + " STime: " + starttime
                                + " Logfile: " + LF.LogFile
                                + " ETime: " + endtime
                                + " Duration: " + LF.GetNiceDuration());

                    }
                }
                //</editor-fold>

                // TODO insert data into tree object based on the time...
                //<editor-fold defaultstate="collapsed" desc="sout SOURCE... ">
                if (debugmode) {
                    Iterator itr = SOURCE.iterator();
                    while (itr.hasNext()) {
                        String str = (String) itr.next();
                        System.out.println("Source: " + SOURCE.indexOf(str) + " - " + str);

                    }
                }
                //</editor-fold>

                if (debugmode) {
                    System.out.println("Starting Points: " + StartPoints);
                }

                ArrayList DataTree = new ArrayList();
                
                //DataTree.add(root);
                StartPoints.clear();

                Iterator itr = LOGS.iterator();
                while (itr.hasNext()) {
                    LogFiles LF = (LogFiles) itr.next();
                    Iterator itr1 = DATA.iterator();
                    while (itr1.hasNext()) {
                        JobEntries JE = (JobEntries) itr1.next();
                        if (LF.GetLogID() == JE.logfile) {

                            if (JE.action == 1) {               // "Job_Extract"
                                TreeNode tmp = root.addChild(JE);
                                DataTree.add(tmp);
                                if (StartPoints.containsKey("Job_Extract")) {
                                    StartPoints.replace("Job_Extract", DataTree.indexOf(tmp));
                                } else {
                                    StartPoints.put("Job_Extract", DataTree.indexOf(tmp));

                                }
                            }

                            if (JE.action == 2) {               // "ExtractedRows"
                                if (StartPoints.containsKey("Job_Extract")) {
                                    TreeNode tmp = (TreeNode) DataTree.get((int) StartPoints.get("Job_Extract"));
                                    int index = DataTree.indexOf(tmp);
                                    //System.out.println("TreeNode from DataTeee: " + tmp.toString());
                                    tmp.addChild(JE);
                                    //tmp.print();
                                    DataTree.set(index, tmp);

                                } //else {
                                //{startpoint doesn't exist 
                                // TODO create virtual startpoint
                            }

                            if (JE.action == 3 ) {                // "Job_TransformGIM"
                                TreeNode tmp = root.addChild(JE);
                                DataTree.add(tmp);
                                if (StartPoints.containsKey("Job_TransformGIM")) {
                                    StartPoints.replace("Job_TransformGIM", DataTree.indexOf(tmp));
                                } else {
                                    StartPoints.put("Job_TransformGIM", DataTree.indexOf(tmp));
                                }
                            }
                            if (JE.action == 4) {                   // "TransformStep"
                                if (StartPoints.containsKey("Job_TransformGIM")) {
                                    TreeNode tmp = (TreeNode) DataTree.get((int) StartPoints.get("Job_TransformGIM"));
                                    int index = DataTree.indexOf(tmp);
                                    tmp.addChild(JE);
                                    DataTree.set(index, tmp);

                                } //else {
                                //{startpoint doesn't exist 
                                // TODO create virtual startpoint
                            }
                            
                            if (JE.action == 5 ) {                  // "Job_AggregateGIM"
                                TreeNode tmp = root.addChild(JE);
                                DataTree.add(tmp);
                                if (StartPoints.containsKey("Job_AggregateGIM")) {
                                    StartPoints.replace("Job_AggregateGIM", DataTree.indexOf(tmp));
                                } else {
                                    StartPoints.put("Job_AggregateGIM", DataTree.indexOf(tmp));
                                }
                            }
                            if (JE.action  == 6 ) {                 // "AggHierarchy"
                                if (StartPoints.containsKey("Job_AggregateGIM")) {
                                    TreeNode tmp = (TreeNode) DataTree.get((int) StartPoints.get("Job_AggregateGIM"));
                                    int index = DataTree.indexOf(tmp);
                                    tmp.addChild(JE);
                                    DataTree.set(index, tmp);

                                } //else {
                                //{startpoint doesn't exist 
                                // TODO create virtual startpoint
                            }
                        }
                    }
                }
                if (debugmode) {
                    System.out.println("root: ");
                    root.print();
                    System.out.println("Starting Points: " + StartPoints);
                }

                //<editor-fold defaultstate="collapsed" desc="verification of DATA content ... ">
                // TODO remove this code
                if (!debugmode) {
                    Iterator itr2 = DATA.iterator();
                    while (itr2.hasNext()) {
                        JobEntries JE = (JobEntries) itr2.next();
                        java.util.Date starttime = new java.util.Date((long) JE.starttime);
                        java.util.Date endtime = new java.util.Date((long) JE.endtime);

                        if ("Job_Extract".equals(JE.action) || "Job_TransformGIM".equals(JE.action)) {
                            System.out.println(
                                    "+-|  " + JE.action
                                    //+ " Logfile:" + JE.logfile
                                    //+ " Line:" + JE.line
                                    //+ " Action:" + 
                                    + "    " + starttime
                            //+ " ETime:" + endtime
                            //+ " Duration:" + JE.duration + "ms"
                            //+ " Raws:" + JE.raws
                            //+ " Comment:" + JE.comment
                            //+ " Custom:" + JE.custom1

                            );

                        } else {
                            System.out.println(
                                    "  |- " + JE.action
                                    //+ " Logfile:" + JE.logfile
                                    //+ " Line:" + JE.line
                                    //+ " Action:" + 
                                    + "    " + starttime
                            //+ " ETime:" + endtime
                            //+ " Duration:" + JE.duration + "ms"
                            //+ " Raws:" + JE.raws
                            //+ " Comment:" + JE.comment
                            //+ " Custom:" + JE.custom1

                            );

                        }

                    }
                }
                // </editor-fold>

            } catch (NullPointerException e) {
                java.util.logging.Logger.getLogger(Gimreader.class.getName()).log(java.util.logging.Level.SEVERE, null, e);
                System.out.println("exceptio: " + e.toString());
                System.out.println("path to log files is incorrect:" + args[0]);
            }
        } else {
            System.out.println("specify path to folder with gim_etl log files in command line");
        }

        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
            //<editor-fold defaultstate="collapsed" desc="catch exceptions">
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Gimreader.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Gimreader.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Gimreader.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Gimreader.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        SwingUtilities.invokeLater(
                new Runnable() {
                    @Override
                    public void run() {
                        createAndShowGUI(root);
                    }
                }
        );

    } // main ends
}
